home *** CD-ROM | disk | FTP | other *** search
/ APDL Other Worlds / APDL Other Worlds Collection.iso / SF3000 / Extras / CBlibrary / c / ViewsMenu < prev   
Encoding:
Text File  |  2003-10-16  |  13.8 KB  |  435 lines

  1. /*
  2.  * CBLibrary - ViewsMenu
  3.  * Copyright (C) 2003  Chris Bazley
  4.  *
  5.  * This library is free software; you can redistribute it and/or
  6.  * modify it under the terms of the GNU Lesser General Public
  7.  * License as published by the Free Software Foundation; either
  8.  * version 2.1 of the License, or (at your option) any later version.
  9.  *
  10.  * This library is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.  * Lesser General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU Lesser General Public
  16.  * License along with this library; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  */
  19.  
  20. /* General code to maintain a list of views and build iconbar menu */
  21.  
  22. /* ANSI library files */
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <stdbool.h>
  27. #include <ctype.h>
  28.  
  29. /* RISC OS library files */
  30. #include "kernel.h"
  31. #include "wimp.h"
  32. #include "toolbox.h"
  33. #include "saveas.h"
  34. #include "window.h"
  35. #include "event.h"
  36. #include "wimplib.h"
  37. #include "menu.h"
  38.  
  39. /* My library files */
  40. #include "err.h"
  41. #include "msgtrans.h"
  42. #include "hourglass.h"
  43. #include "Macros.h"
  44. #include "ViewsMenu.h"
  45.  
  46. typedef struct _ViewInfo {
  47.   ObjectId object;
  48.   char name[256]; /* to show in menu */
  49.   char *file_path; /* to avoid loading duplicate files */
  50.   bool remove_me;
  51.   struct _ViewInfo *next;
  52. } ViewInfo;
  53.  
  54. static ComponentId VM_parent_entry;
  55. static ViewInfo *view_list;
  56. static ObjectId VM, VM_parent;
  57. static bool menu_showing = false, removals_pending = false;
  58. extern _kernel_oserror shared_err_block;
  59.  
  60. /* ----------------------------------------------------------------------- */
  61. /*                       Function prototypes                               */
  62.  
  63. static ToolboxEventHandler _ViewsMenu_parentopenhandler, _ViewsMenu_clickhandler, _ViewsMenu_parentclosehandler;
  64.  
  65. /* ----------------------------------------------------------------------- */
  66. /*                         Public functions                                */
  67.  
  68. _kernel_oserror *ViewsMenu_create(void)
  69. {
  70.   /* Call to create views menu (before any other function!) */
  71.  
  72.   /* Create menu */
  73.   THROW(toolbox_create_object(0, "ViewsMenu", &VM))
  74.  
  75.   /* Listen for clicks */
  76.   return event_register_toolbox_handler(VM, Menu_Selection, _ViewsMenu_clickhandler, NULL);
  77. }
  78.  
  79. /* ----------------------------------------------------------------------- */
  80.  
  81. _kernel_oserror *ViewsMenu_parentcreated(ObjectId parent_menu, ComponentId parent_entry)
  82. {
  83.   /* To be called when parent menu is created */
  84.   VM_parent_entry = parent_entry;
  85.   VM_parent = parent_menu;
  86.  
  87.   /* Register event handlers for when parent is opened and closed */
  88.   THROW(event_register_toolbox_handler(parent_menu, Menu_AboutToBeShown, _ViewsMenu_parentopenhandler, NULL))
  89.   return event_register_toolbox_handler(parent_menu, Menu_HasBeenHidden, _ViewsMenu_parentclosehandler, NULL);
  90. }
  91.  
  92. /* ----------------------------------------------------------------------- */
  93.  
  94. _kernel_oserror *ViewsMenu_setname(ObjectId showobject, char *view_name, char *file_path)
  95. {
  96.   ViewInfo *scan_views;
  97.   char *new_ptr;
  98.   
  99.   scan_views = view_list;
  100.   while(scan_views != NULL) {
  101.     if(scan_views->object == showobject && !scan_views->remove_me ) {
  102.       /* Found specified menu entry */
  103.       if(file_path != NULL) {
  104.         /* Change filepath associated with this menu entry */
  105.         new_ptr = malloc(strlen(file_path)+1);
  106.         if(new_ptr == NULL) {
  107.           WRITE_GERR(shared_err_block, "NoMem");
  108.           return &shared_err_block;
  109.         }
  110.         strcpy(new_ptr, file_path);
  111.         free(scan_views->file_path);
  112.         scan_views->file_path = new_ptr;
  113.       }
  114.       if(view_name != NULL) {
  115.         /* Change text for this menu entry */
  116.         THROW(menu_set_entry_text(0, VM, (ComponentId)scan_views, view_name))
  117.       }
  118.       return NULL; /* success */
  119.     }
  120.     scan_views = scan_views->next;
  121.   }
  122.  
  123.   strncpy(shared_err_block.errmess, "ObjectId not found (ViewsMenu_setname)", sizeof(shared_err_block.errmess)-1);
  124.   return &shared_err_block; /* not found */
  125. }
  126.  
  127. /* ----------------------------------------------------------------------- */
  128.  
  129. ObjectId ViewMenu_getfirst(void)
  130. {
  131.   ViewInfo *scan_views;
  132.  
  133.   scan_views = view_list;
  134.   while(scan_views != NULL) {
  135.     if(!scan_views->remove_me)
  136.       return view_list->object; /* success */
  137.     scan_views = scan_views->next;
  138.   }
  139.   return NULL_ObjectId; /* not found */
  140. }
  141.  
  142. /* ----------------------------------------------------------------------- */
  143.  
  144. ObjectId ViewMenu_getnext(ObjectId current)
  145. {
  146.   ViewInfo *scan_views;
  147.   
  148.   scan_views = view_list;
  149.   while(scan_views != NULL) {
  150.     if(scan_views->object == current && !scan_views->remove_me
  151.     && scan_views->next != NULL && !scan_views->next->remove_me)
  152.       return scan_views->next->object; /* found */
  153.  
  154.     scan_views = scan_views->next;
  155.   }
  156.   
  157.   return NULL_ObjectId;  /* 'current' view not found, or end of list */
  158. }
  159.  
  160. /* ----------------------------------------------------------------------- */
  161.  
  162. _kernel_oserror *ViewsMenu_add(ObjectId showobject, char *view_name, char *file_path)
  163. {
  164.   ViewInfo *new_view;
  165.   MenuTemplateEntry Entry = {0};
  166.   ViewInfo *scan_views;
  167.   _kernel_oserror *errptr;
  168.   
  169.   /* Check not already on list */
  170.   scan_views = view_list;
  171.   while(scan_views != NULL) {
  172.     if(scan_views->object == showobject && !scan_views->remove_me) {
  173.       strncpy(shared_err_block.errmess, "Duplicate ObjectId (ViewsMenu_add)", sizeof(shared_err_block.errmess)-1);
  174.       return &shared_err_block;
  175.     }
  176.     scan_views = scan_views->next;
  177.   }
  178.   
  179.   /* Create new menu entry */
  180.   new_view = malloc(sizeof(ViewInfo));
  181.   if(new_view == NULL) {
  182.     WRITE_GERR(shared_err_block, "NoMem");
  183.     return &shared_err_block;
  184.   }
  185.  
  186.   /* Set entry text, and associated toolbox object & filepath */
  187.   new_view->remove_me = false;
  188.   new_view->file_path = malloc(strlen(file_path)+1);
  189.   if(new_view->file_path == NULL) {
  190.     free(new_view);
  191.     WRITE_GERR(shared_err_block, "NoMem");
  192.     return &shared_err_block; /* failure */
  193.   }
  194.   strcpy(new_view->file_path, file_path);
  195.   new_view->object = showobject;
  196.   strncpy(new_view->name, view_name, sizeof(new_view->name)-1);
  197.  
  198.   /* Add entry to menu */
  199.   Entry.text = new_view->name;
  200.   Entry.max_text = sizeof(new_view->name);
  201.   Entry.component_id = (ComponentId)new_view;
  202.   errptr = menu_add_entry(0, VM, Menu_AddEntryAtEnd, (char *) &Entry, 0);
  203.   if(errptr != NULL) {
  204.     free(new_view->file_path);
  205.     free(new_view);
  206.     return errptr; /* failure */
  207.   }
  208.   
  209.   /* Link new menu entry into list */
  210.   new_view->next = view_list;
  211.   view_list = new_view;
  212.   
  213.   return NULL; /* success */
  214. }
  215.  
  216. /* ----------------------------------------------------------------------- */
  217.  
  218. _kernel_oserror *ViewsMenu_showall(void)
  219. {
  220.   /* Bring all open windows to the front */
  221.   ViewInfo *scan_views;
  222.   ObjectId parent;
  223.   unsigned int state;
  224.   ComponentId parent_component;
  225.   
  226.   scan_views = view_list;
  227.   while(scan_views != NULL) {
  228.     if(!scan_views->remove_me) {
  229.       /* Show object using existing parent */
  230.       THROW(toolbox_get_parent(0, scan_views->object, &parent, &parent_component))
  231.       /* Trap incase parent no longer exists */
  232.       if(toolbox_get_object_state(0, parent, &state) != NULL) {
  233.         parent = NULL_ObjectId;
  234.         parent_component = NULL_ComponentId;
  235.       }
  236.       THROW(ViewsMenu_show_object(0, scan_views->object, Toolbox_ShowObject_Default, NULL, parent, parent_component))
  237.       
  238.       scan_views = scan_views->next;
  239.     }
  240.   }
  241.   return NULL; /* success */
  242. }
  243.  
  244. /* ----------------------------------------------------------------------- */
  245.  
  246. _kernel_oserror *ViewsMenu_remove(ObjectId showobject)
  247. {
  248.   /* Remove a window from the list */
  249.   ViewInfo *scan_views, *prev_view;
  250.  
  251.   scan_views = view_list;
  252.   prev_view = NULL;
  253.   while(scan_views != NULL) {
  254.     if(scan_views->object == showobject
  255.     && !scan_views->remove_me) {
  256.       free(scan_views->file_path); /* can immediately do without wasting this memory */
  257.       /* Is views menu showing? */
  258.       if(menu_showing) {
  259.         /* Removing entry seems to cause trouble if menu is open */
  260.         scan_views->remove_me = true;
  261.         removals_pending = true;
  262.         /* (Removal defered until menu closes. Must keep linked list record or we will lose the ComponentId of the menu entry.) */
  263.       }
  264.       else {
  265.         /* Menu is closed - safe to remove menu entry */
  266.         THROW(menu_remove_entry(0, VM, (ComponentId)scan_views))
  267.       
  268.         /* Link over record */
  269.         if(scan_views == view_list)
  270.           view_list = scan_views->next;
  271.         else
  272.           prev_view->next = scan_views->next;
  273.         free(scan_views);
  274.       }
  275.       return  NULL; /* success */
  276.     }
  277.     prev_view = scan_views;
  278.     scan_views = scan_views->next;
  279.   }
  280.   strncpy(shared_err_block.errmess, "ObjectId not found (ViewsMenu_remove)", sizeof(shared_err_block.errmess)-1);
  281.   return &shared_err_block; /* not found */
  282. }
  283.  
  284. /* ----------------------------------------------------------------------- */
  285.  
  286. ObjectId ViewsMenu_findview(char *file_path_to_match)
  287. {
  288.   /* Find a view matching the specified name */
  289.   ViewInfo *scan_views;
  290.   
  291.   scan_views = view_list;
  292.   while(scan_views != NULL) {
  293.     if(ViewsMenu_strcmp_nc(scan_views->file_path, file_path_to_match)
  294.     && !scan_views->remove_me)
  295.       return scan_views->object; /* found matching path */
  296.     scan_views = scan_views->next;
  297.   }
  298.   return NULL_ObjectId; /* not found */
  299. }
  300.  
  301. /* ----------------------------------------------------------------------- */
  302.  
  303. bool ViewsMenu_strcmp_nc(const char *string1, const char *string2)
  304. {
  305.   /* Determines whether two strings are equal, case insensitive */
  306.   int i = 0;
  307.   while(string1[i] != 0 && string2[i] != 0
  308.   && tolower((int)string1[i]) == tolower((int)string2[i]))
  309.     i++;
  310.   if(string1[i] == 0 && string2[i] == 0)
  311.     return true; /* reached string terminators */
  312.   return false; /* finished early due to mismatch */  
  313. }
  314.  
  315. /* ----------------------------------------------------------------------- */
  316.  
  317. _kernel_oserror *ViewsMenu_show_object(unsigned int flags, ObjectId id, int show_type, void *type, ObjectId parent, ComponentId parent_component)
  318. {
  319.   /* This addresses the problem of iconised windows being re-opened independently by an application, yet remaining on the pinboard */
  320.  
  321.   THROW(toolbox_show_object(flags, id, show_type, type, parent, parent_component))
  322.  
  323.   ObjectClass obj_class;
  324.   THROW(toolbox_get_object_class(0, id, &obj_class))
  325.   if(obj_class == SaveAs_ObjectClass)
  326.     THROW(saveas_get_window_id(0, id, &id))
  327.   else {
  328.     if(obj_class != Window_ObjectClass)
  329.       return NULL; /* don't know about other classes */
  330.   }
  331.  
  332.   /* Get wimp handle of underlying window */    
  333.   WimpMessage msg_block;
  334.   THROW(window_get_wimp_handle(0, id, &msg_block.data.words[0]))
  335.  
  336.   /* Broadcast message &400CB (window closed) in case it is iconised */
  337.   msg_block.hdr.size = sizeof(msg_block.hdr) + sizeof(int);
  338.   msg_block.hdr.your_ref = 0;
  339.   msg_block.hdr.action_code = Wimp_MWindowClosed;
  340.   return wimp_send_message(Wimp_EUserMessage, &msg_block, 0, 0, NULL);
  341. }
  342.  
  343. /* ----------------------------------------------------------------------- */
  344. /*                         Private functions                               */
  345.  
  346. static int _ViewsMenu_parentopenhandler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
  347. {
  348.   /* Parent of views menu is about to open */
  349.   NOT_USED(event_code)
  350.   NOT_USED(event)
  351.   NOT_USED(handle)
  352.  
  353.   /* If linked list is empty then grey views submenu entry */
  354.   RE(menu_set_fade(0, id_block->self_id, VM_parent_entry, (view_list == NULL)))
  355.   
  356.   menu_showing = true; /* we need to defer deletions until menu closes */
  357.   
  358.   return 0; /* pass event on (not our menu!) */
  359. }
  360.  
  361. /* ----------------------------------------------------------------------- */
  362.  
  363. static int _ViewsMenu_parentclosehandler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
  364. {
  365.   /* Parent of views menu has closed */
  366.   ViewInfo *scan_views, *prev_view, *delscan_view;
  367.   NOT_USED(event_code)
  368.   NOT_USED(event)
  369.   NOT_USED(id_block)
  370.   NOT_USED(handle)
  371.   
  372.   menu_showing = false; /* we no longer need to defer deletions */
  373.   
  374.   if(removals_pending) {
  375.     /* Remove any entries on views menu that have been greyed out (i.e. window closed) */
  376.     scan_views = view_list;
  377.     prev_view = NULL;
  378.     while(scan_views != NULL) {
  379.       if(scan_views->remove_me) {
  380.         /* Remove menu entry */
  381.         RE(menu_remove_entry(0, VM, (ComponentId)scan_views))
  382.         delscan_view = scan_views;
  383.         scan_views = delscan_view->next;
  384.         /* (prev_view stays the same - record before deleted record) */
  385.         
  386.         /* Link over record */
  387.         if(view_list == delscan_view)
  388.           view_list = scan_views;
  389.         else
  390.           prev_view->next = scan_views;
  391.         free(delscan_view);
  392.       }
  393.       else {
  394.         /* roll onto next record in linked list */
  395.         prev_view = scan_views;
  396.         scan_views = scan_views->next;
  397.       }
  398.     }
  399.     removals_pending = false;
  400.   }
  401.   return 1; /* claim event */
  402. }
  403.  
  404. /* ----------------------------------------------------------------------- */
  405.  
  406. static int _ViewsMenu_clickhandler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
  407. {
  408.   ViewInfo *view_info;
  409.   ObjectId parent;
  410.   ComponentId parent_component;
  411.   unsigned int state;
  412.   NOT_USED(event_code)
  413.   NOT_USED(event)
  414.   NOT_USED(handle)
  415.  
  416.   view_info = (ViewInfo *)id_block->self_component;
  417.   if(view_info->remove_me) {
  418.     _kernel_oswrch(7); /* beep */
  419.     return 1; /* object no longer exists */
  420.   }
  421.  
  422.   /* Get parent of object associated with this menu entry */
  423.   E_RETV(toolbox_get_parent(0, view_info->object, &parent, &parent_component), 1)
  424.   
  425.   /* Trap incase parent no longer exists */
  426.   if(toolbox_get_object_state(0, parent, &state) != NULL) {
  427.     parent = NULL_ObjectId;
  428.     parent_component = NULL_ComponentId;
  429.   }
  430.   /* Re-open, preserving current parent */
  431.   RE(ViewsMenu_show_object(0, view_info->object, Toolbox_ShowObject_Default, NULL, parent, parent_component))
  432.   
  433.   return 1; /* claim event */
  434. }
  435.